home *** CD-ROM | disk | FTP | other *** search
/ NeXT Education Software Sampler 1992 Fall / NeXT Education Software Sampler 1992 Fall.iso / Programming / Source / winterp-1.13 / src-server / xlisp / xldmem.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-10-04  |  22.0 KB  |  953 lines

  1. /* -*-C-*-
  2. ********************************************************************************
  3. *
  4. * File:         xldmem.c
  5. * RCS:          $Header: xldmem.c,v 1.8 91/03/24 22:24:34 mayer Exp $
  6. * Description:  xlisp dynamic memory management routines.
  7. * Author:       David Michael Betz; Niels Mayer
  8. * Created:      
  9. * Modified:     Fri Oct  4 03:36:28 1991 (Niels Mayer) mayer@hplnpm
  10. * Language:     C
  11. * Package:      N/A
  12. * Status:       X11r5 contrib tape release
  13. *
  14. * WINTERP Copyright 1989, 1990, 1991 Hewlett-Packard Company (by Niels Mayer).
  15. * XLISP version 2.1, Copyright (c) 1989, by David Betz.
  16. *
  17. * Permission to use, copy, modify, distribute, and sell this software and its
  18. * documentation for any purpose is hereby granted without fee, provided that
  19. * the above copyright notice appear in all copies and that both that
  20. * copyright notice and this permission notice appear in supporting
  21. * documentation, and that the name of Hewlett-Packard and David Betz not be
  22. * used in advertising or publicity pertaining to distribution of the software
  23. * without specific, written prior permission.  Hewlett-Packard and David Betz
  24. * make no representations about the suitability of this software for any
  25. * purpose. It is provided "as is" without express or implied warranty.
  26. *
  27. * HEWLETT-PACKARD AND DAVID BETZ DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
  28. * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
  29. * IN NO EVENT SHALL HEWLETT-PACKARD NOR DAVID BETZ BE LIABLE FOR ANY SPECIAL,
  30. * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  31. * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  32. * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  33. * PERFORMANCE OF THIS SOFTWARE.
  34. *
  35. * See ./winterp/COPYRIGHT for information on contacting the authors.
  36. * Please send modifications, improvements and bugfixes to mayer@hplabs.hp.com
  37. * Post XLISP-specific questions/information to the newsgroup comp.lang.lisp.x
  38. *
  39. ********************************************************************************
  40. */
  41. static char rcs_identity[] = "@(#)$Header: xldmem.c,v 1.8 91/03/24 22:24:34 mayer Exp $";
  42.  
  43.  
  44. #include "xlisp.h"
  45.  
  46. /* node flags */
  47. #define MARK    1
  48. #define LEFT    2
  49.  
  50. /* macro to compute the size of a segment */
  51. #define segsize(n) (sizeof(SEGMENT)+((n)-1)*sizeof(struct node))
  52.  
  53. /* external variables */
  54. extern LVAL obarray,s_gcflag,s_gchook,s_unbound,true;
  55. extern LVAL xlenv,xlfenv,xldenv;
  56. extern char buf[];
  57.  
  58. /* variables local to xldmem.c and xlimage.c */
  59. SEGMENT *segs,*lastseg,*fixseg,*charseg;
  60. int anodes,nsegs,gccalls;
  61. long nnodes,nfree,total;
  62. LVAL fnodes;
  63.  
  64. /* external procedures */
  65. extern char *malloc();
  66. extern char *calloc();
  67.  
  68. /* forward declarations */
  69. LOCAL FORWARD LVAL newnode();    /* NPM: changed this to LOCAL */
  70. LOCAL FORWARD unsigned char *stralloc(); /* NPM: changed this to LOCAL */
  71. FORWARD SEGMENT *newsegment();
  72.  
  73. #if (defined(UNIX) || defined(WINTERP))
  74. /* cv_pipe - allocate and initialize a new XLTYPE_PIPE node, which uses same node structure as STREAM (see cvfile())  */
  75. LVAL cv_pipe(fp)
  76.      FILE *fp;
  77. {
  78.   LVAL val;
  79.   val = newnode(XLTYPE_PIPE);
  80.   setfile(val,fp);
  81.   setsavech(val,'\0');
  82.   return (val);
  83. }
  84. #endif /* (defined(UNIX) || defined(WINTERP)) */
  85.  
  86. #ifdef WINTERP
  87.  
  88. extern LVAL v_savedobjs;
  89. extern void Wxms_Garbage_Collect_XmString(); /* w_XmString.c */
  90. extern void Wpm_Decr_Refcount_Or_Free_Pixmap();    /* w_pixmap.c */
  91. extern void Wcls_Garbage_Collect_WIDGETOBJ(); /* w_classes.c */
  92.  
  93. /* cv_xtresource - convert a xtresource instance to an XLTYPE_XT_RESOURCE node */
  94. LVAL cv_xtresource(res)
  95.      struct _Resource_Instance *res;
  96. {
  97.   LVAL val;
  98.   val = newnode(XLTYPE_XT_RESOURCE);
  99.   val->n_xtresource = res;
  100.   return (val);
  101. }
  102.  
  103. /* cv_pixel - convert a Pixel to an XLTYPE_Pixel node */
  104. LVAL cv_pixel(pixel)
  105.      Pixel pixel;
  106. {
  107.   LVAL val;
  108.   val = newnode(XLTYPE_Pixel);
  109.   val->n_pixel = pixel;
  110.   return (val);
  111. }
  112.  
  113. /* cv_pixmap - allocate and initialize a new XLTYPE_Pixmap node */
  114. LVAL cv_pixmap(pixmap)
  115.      Pixmap pixmap;
  116. {
  117.   LVAL val;
  118.   val = newnode(XLTYPE_Pixmap);
  119.   val->n_pixmap = pixmap;
  120.   return (val);
  121. }
  122.  
  123. /* cv_ximage -- allocate and initialize a new XLTYPE_XImage node */
  124. LVAL cv_ximage(ximage)
  125.      XImage *ximage;
  126. {
  127.   LVAL val;
  128.   val = newnode(XLTYPE_XImage);
  129.   val->n_ximage = ximage;
  130.   return (val);
  131. }
  132.  
  133. /* cv_xmstring -- allocate and initialize a new XLTYPE_XmString node */
  134. LVAL cv_xmstring(xmstr)
  135.      XmString xmstr;
  136. {
  137.   LVAL val;
  138.   val = newnode(XLTYPE_XmString);
  139.   val->n_xmstring = xmstr;
  140.   return (val);
  141. }
  142.  
  143. /* cv_xevent_ptr -- allocate and initialize a new XLTYPE_XEvent node */
  144. LVAL cv_xevent(xevp)
  145.      XEvent *xevp;
  146. {
  147.   LVAL val;
  148.   val = newnode(XLTYPE_XEvent);
  149.   val->n_xevent = xevp;
  150.   return (val);
  151. }
  152.  
  153. /* cv_window -- allocate and initialize a new XLTYPE_Window node */
  154. LVAL cv_window(win)
  155.      Window win;
  156. {
  157.   LVAL val;
  158.   val = newnode(XLTYPE_Window);
  159.   val->n_window = win;
  160.   return (val);
  161. }
  162.  
  163. /* cv_xtaccelerators -- allocate and initialize a new XLTYPE_XtAccelerators node */
  164. LVAL cv_xtaccelerators(axl)
  165.      XtAccelerators axl;
  166. {
  167.   LVAL val;
  168.   val = newnode(XLTYPE_XtAccelerators);
  169.   val->n_xtaccelerators = axl;
  170.   return (val);
  171. }
  172.  
  173. /* cv_xttranslations -- allocate and initialize a new XLTYPE_XtTranslations node */
  174. LVAL cv_xttranslations(txl)
  175.      XtTranslations txl;
  176. {
  177.   LVAL val;
  178.   val = newnode(XLTYPE_XtTranslations);
  179.   val->n_xttranslations = txl;
  180.   return (val);
  181. }
  182.  
  183. /* cv_string - allocate and initialize a new STRING node.     */
  184. /* WARNING: use cvstring() to make a copy of the string ...   */
  185. /* the string passed will get freed during garbage collection */
  186. LVAL cv_string(str)
  187.      char* str;
  188. {
  189.   LVAL val;
  190.   val = newnode(STRING);
  191.   val->n_strlen = strlen(str) + 1;
  192.   val->n_string = (unsigned char*) str;
  193.   return (val);
  194. }
  195.  
  196. /* new_pixrefobj() -- allocate and initialize a new XLTYPE_PIXMAP_REFOBJ */
  197. LVAL new_pixrefobj()
  198. {
  199.   LVAL val;
  200.   val = newvector(PIXMAP_REFOBJ_SIZE);
  201.   val->n_type = XLTYPE_PIXMAP_REFOBJ;
  202.   return (val);
  203. }
  204.  
  205. /* new_callbackobj() -- allocate and initialize a new XLTYPE_CALLBACKOBJ */
  206. LVAL new_callbackobj()
  207. {
  208.   LVAL val;
  209.   val = newvector(CALLBACKOBJ_SIZE);
  210.   val->n_type = XLTYPE_CALLBACKOBJ;
  211.   return (val);
  212. }
  213.  
  214. /* new_timeoutobj() -- allocate and initialize a new XLTYPE_TIMEOUTOBJ */
  215. LVAL new_timeoutobj()
  216. {
  217.   LVAL val;
  218.   val = newvector(TIMEOUTOBJ_SIZE);
  219.   val->n_type = XLTYPE_TIMEOUTOBJ;
  220.   return (val);
  221. }
  222.  
  223. /* new_evhandlerobj() -- allocate and initialize a new XLTYPE_EVHANDLEROBJ */
  224. LVAL new_evhandlerobj()
  225. {
  226.   LVAL val;
  227.   val = newvector(EVHANDLEROBJ_SIZE);
  228.   val->n_type = XLTYPE_EVHANDLEROBJ;
  229.   return (val);
  230. }
  231.  
  232. #endif                /* WINTERP */
  233.  
  234. /* cons - construct a new cons node */
  235. LVAL cons(x,y)
  236.   LVAL x,y;
  237. {
  238.     LVAL nnode;
  239.  
  240.     /* get a free node */
  241.     if ((nnode = fnodes) == NIL) {
  242.     xlstkcheck(2);
  243.     xlprotect(x);
  244.     xlprotect(y);
  245.     findmem();
  246.     if ((nnode = fnodes) == NIL)
  247.         xlabort("insufficient node space");
  248.     xlpop();
  249.     xlpop();
  250.     }
  251.  
  252.     /* unlink the node from the free list */
  253.     fnodes = cdr(nnode);
  254.     --nfree;
  255.  
  256.     /* initialize the new node */
  257.     nnode->n_type = CONS;
  258.     rplaca(nnode,x);
  259.     rplacd(nnode,y);
  260.  
  261.     /* return the new node */
  262.     return (nnode);
  263. }
  264.  
  265. /* cvstring - convert a string to a string node */
  266. LVAL cvstring(str)
  267.   char *str;
  268. {
  269.     LVAL val;
  270.     xlsave1(val);
  271.     val = newnode(STRING);
  272.     val->n_strlen = strlen(str) + 1;
  273.     val->n_string = stralloc(getslength(val));
  274.     strcpy(getstring(val),str);
  275.     xlpop();
  276.     return (val);
  277. }
  278.  
  279. /* newstring - allocate and initialize a new string */
  280. LVAL newstring(size)
  281.   int size;
  282. {
  283.     LVAL val;
  284.     xlsave1(val);
  285.     val = newnode(STRING);
  286.     val->n_strlen = size;
  287.     val->n_string = stralloc(getslength(val));
  288.     strcpy(getstring(val),"");
  289.     xlpop();
  290.     return (val);
  291. }
  292.  
  293. /* cvsymbol - convert a string to a symbol */
  294. LVAL cvsymbol(pname)
  295.   char *pname;
  296. {
  297.     LVAL val;
  298.     xlsave1(val);
  299.     val = newvector(SYMSIZE);
  300.     val->n_type = SYMBOL;
  301.     setvalue(val,s_unbound);
  302.     setfunction(val,s_unbound);
  303.     setpname(val,cvstring(pname));
  304.     xlpop();
  305.     return (val);
  306. }
  307.  
  308. /* cvsubr - convert a function to a subr or fsubr */
  309. LVAL cvsubr(fcn,type,offset)
  310.   LVAL (*fcn)(); int type,offset;
  311. {
  312.     LVAL val;
  313.     val = newnode(type);
  314.     val->n_subr = fcn;
  315.     val->n_offset = offset;
  316.     return (val);
  317. }
  318.  
  319. /* cvfile - convert a file pointer to a stream */
  320. LVAL cvfile(fp)
  321.   FILE *fp;
  322. {
  323.     LVAL val;
  324.     val = newnode(STREAM);
  325.     setfile(val,fp);
  326.     setsavech(val,'\0');
  327.     return (val);
  328. }
  329.  
  330. /* cvfixnum - convert an integer to a fixnum node */
  331. LVAL cvfixnum(n)
  332.   FIXTYPE n;
  333. {
  334.     LVAL val;
  335.     if (n >= SFIXMIN && n <= SFIXMAX)
  336.     return (&fixseg->sg_nodes[(int)n-SFIXMIN]);
  337.     val = newnode(FIXNUM);
  338.     val->n_fixnum = n;
  339.     return (val);
  340. }
  341.  
  342. /* cvflonum - convert a floating point number to a flonum node */
  343. LVAL cvflonum(n)
  344.   FLOTYPE n;
  345. {
  346.     LVAL val;
  347.     val = newnode(FLONUM);
  348.     val->n_flonum = n;
  349.     return (val);
  350. }
  351.  
  352. /* cvchar - convert an integer to a character node */
  353. LVAL cvchar(n)
  354.   int n;
  355. {
  356.     if (n >= CHARMIN && n <= CHARMAX)
  357.     return (&charseg->sg_nodes[n-CHARMIN]);
  358.     xlerror("character code out of range",cvfixnum((FIXTYPE)n));
  359. }
  360.  
  361. /* newustream - create a new unnamed stream */
  362. LVAL newustream()
  363. {
  364.     LVAL val;
  365.     val = newnode(USTREAM);
  366.     sethead(val,NIL);
  367.     settail(val,NIL);
  368.     return (val);
  369. }
  370.  
  371. /* newobject - allocate and initialize a new object */
  372. LVAL newobject(cls,size)
  373.   LVAL cls; int size;
  374. {
  375.     LVAL val;
  376.     val = newvector(size+1);
  377.     val->n_type = OBJECT;
  378.     setelement(val,0,cls);
  379.     return (val);
  380. }
  381.  
  382. /* newclosure - allocate and initialize a new closure */
  383. LVAL newclosure(name,type,env,fenv)
  384.   LVAL name,type,env,fenv;
  385. {
  386.     LVAL val;
  387.     val = newvector(CLOSIZE);
  388.     val->n_type = CLOSURE;
  389.     setname(val,name);
  390.     settype(val,type);
  391.     setenv(val,env);
  392.     setfenv(val,fenv);
  393.     return (val);
  394. }
  395.  
  396. /* newstruct - allocate and initialize a new structure node */
  397. LVAL newstruct(type,size)
  398.   LVAL type; int size;
  399. {
  400.     LVAL val;
  401.     val = newvector(size+1);
  402.     val->n_type = STRUCT;
  403.     setelement(val,0,type);
  404.     return (val);
  405. }
  406.  
  407. /* newvector - allocate and initialize a new vector node */
  408. LVAL newvector(size)
  409.   int size;
  410. {
  411.     LVAL vect;
  412.     int bsize;
  413.     xlsave1(vect);
  414.     vect = newnode(VECTOR);
  415.     vect->n_vsize = 0;
  416.     if (bsize = size * sizeof(LVAL)) {
  417.     if ((vect->n_vdata = (LVAL *)calloc(1,bsize)) == NULL) {
  418.         findmem();
  419.         if ((vect->n_vdata = (LVAL *)calloc(1,bsize)) == NULL)
  420.         xlfail("insufficient vector space");
  421.     }
  422.     vect->n_vsize = size;
  423.     total += (long) bsize;
  424.     }
  425.     xlpop();
  426.     return (vect);
  427. }
  428.  
  429. /* newnode - allocate a new node */
  430. LOCAL LVAL newnode(type)
  431.   int type;
  432. {
  433.     LVAL nnode;
  434.  
  435.     /* get a free node */
  436.     if ((nnode = fnodes) == NIL) {
  437.     findmem();
  438.     if ((nnode = fnodes) == NIL)
  439.         xlabort("insufficient node space");
  440.     }
  441.  
  442.     /* unlink the node from the free list */
  443.     fnodes = cdr(nnode);
  444.     nfree -= 1L;
  445.  
  446.     /* initialize the new node */
  447.     nnode->n_type = type;
  448.     rplacd(nnode,NIL);
  449.  
  450.     /* return the new node */
  451.     return (nnode);
  452. }
  453.  
  454. /* stralloc - allocate memory for a string adding a byte for the terminator */
  455. LOCAL unsigned char *stralloc(size)
  456.   int size;
  457. {
  458.     unsigned char *sptr;
  459.  
  460.     /* allocate memory for the string copy */
  461.     if ((sptr = (unsigned char *)malloc(size)) == NULL) {
  462.     gc();  
  463.     if ((sptr = (unsigned char *)malloc(size)) == NULL)
  464.         xlfail("insufficient string space");
  465.     }
  466.     total += (long)size;
  467.  
  468.     /* return the new string memory */
  469.     return (sptr);
  470. }
  471.  
  472. /* findmem - find more memory by collecting then expanding */
  473. LOCAL findmem()
  474. {
  475.     gc();
  476.     if (nfree < (long)anodes)
  477.     addseg();
  478. }
  479.  
  480. /* gc - garbage collect (only called here and in xlimage.c) */
  481. gc()
  482. {
  483.     register LVAL **p,*ap,tmp;
  484.     char buf[STRMAX+1];
  485.     LVAL *newfp,fun;
  486.  
  487.     /* print the start of the gc message */
  488.     if (s_gcflag && getvalue(s_gcflag)) {
  489.     sprintf(buf,"[ gc: total %ld, ",nnodes);
  490.     stdputstr(buf);
  491.     }
  492.  
  493. #ifdef WINTERP
  494.     /* mark the callback-obj's, timeout-obj's, etc that are "referenced"
  495.        inside Motif/Xtoolkit implementation. */
  496.     if (v_savedobjs)
  497.         mark(v_savedobjs);
  498. #endif
  499.  
  500.     /* mark the obarray, the argument list and the current environment */
  501.     if (obarray)
  502.     mark(obarray);
  503.     if (xlenv)
  504.     mark(xlenv);
  505.     if (xlfenv)
  506.     mark(xlfenv);
  507.     if (xldenv)
  508.     mark(xldenv);
  509.  
  510.     /* mark the evaluation stack */
  511.     for (p = xlstack; p < xlstktop; ++p)
  512.     if (tmp = **p)
  513.         mark(tmp);
  514.  
  515.     /* mark the argument stack */
  516.     for (ap = xlargstkbase; ap < xlsp; ++ap)
  517.     if (tmp = *ap)
  518.         mark(tmp);
  519.  
  520.     /* sweep memory collecting all unmarked nodes */
  521.     sweep();
  522.  
  523.     /* count the gc call */
  524.     ++gccalls;
  525.  
  526.     /* call the *gc-hook* if necessary */
  527.     if (s_gchook && (fun = getvalue(s_gchook))) {
  528.     newfp = xlsp;
  529.     pusharg(cvfixnum((FIXTYPE)(newfp - xlfp)));
  530.     pusharg(fun);
  531.     pusharg(cvfixnum((FIXTYPE)2));
  532.     pusharg(cvfixnum((FIXTYPE)nnodes));
  533.     pusharg(cvfixnum((FIXTYPE)nfree));
  534.     xlfp = newfp;
  535.     xlapply(2);
  536.     }
  537.  
  538.     /* print the end of the gc message */
  539.     if (s_gcflag && getvalue(s_gcflag)) {
  540.     sprintf(buf,"%ld free ]\n",nfree);
  541.     stdputstr(buf);
  542.     }
  543. }
  544.  
  545. /* mark - mark all accessible nodes */
  546. LOCAL mark(ptr)
  547.   LVAL ptr;
  548. {
  549.     register LVAL this,prev,tmp;
  550.     int type,i,n;
  551.  
  552.     /* initialize */
  553.     prev = NIL;
  554.     this = ptr;
  555.  
  556.     /* mark this list */
  557.     for (;;) {
  558.  
  559.     /* descend as far as we can */
  560.     while (!(this->n_flags & MARK))
  561.  
  562.         /* check cons and unnamed stream nodes */
  563.         if ((type = ntype(this)) == CONS || type == USTREAM) {
  564.         if (tmp = car(this)) {
  565.             this->n_flags |= MARK|LEFT;
  566.             rplaca(this,prev);
  567.         }
  568.         else if (tmp = cdr(this)) {
  569.             this->n_flags |= MARK;
  570.             rplacd(this,prev);
  571.         }
  572.         else {                /* both sides nil */
  573.             this->n_flags |= MARK;
  574.             break;
  575.         }
  576.         prev = this;            /* step down the branch */
  577.         this = tmp;
  578.         }
  579.  
  580.         /* mark other node types */
  581.         else {
  582.         this->n_flags |= MARK;
  583.         switch (type) {
  584. #ifdef WINTERP
  585.         case XLTYPE_WIDGETOBJ:
  586.           /* 
  587.            * An XLTYPE_WIDGETOBJ is just like a OBJECT node with slot 0
  588.            * being the class, and the other slots being instance
  589.            * variables. class WIDGET_CLASS defines a special instance
  590.            * variable at slot 1 holding the WidgetID. Since that slot
  591.            * isn't an LVAL, it should not be mark()'d. Any additional
  592.            * slots means that the WIDGETOBJ was subclassed and new
  593.            * instance variables were added in the subclass which need to
  594.            * be marked.
  595.            */
  596.           if (tmp = getelement(this, 0))
  597.             mark(tmp);
  598.           /* HACK: skip element 1 since it's special, start at 2 */
  599.           for (i = 2, n = getsize(this) - 2; --n >= 0; ++i)
  600.             if ((tmp = getelement(this,i)))
  601.               mark(tmp);
  602.           break;
  603.         case XLTYPE_TIMEOUTOBJ:
  604.         case XLTYPE_CALLBACKOBJ:
  605.         case XLTYPE_PIXMAP_REFOBJ:
  606.         case XLTYPE_EVHANDLEROBJ:
  607. #endif
  608.         case SYMBOL:
  609.         case OBJECT:
  610.         case VECTOR:
  611.         case CLOSURE:
  612.         case STRUCT:
  613.             for (i = 0, n = getsize(this); --n >= 0; ++i)
  614.             if (tmp = getelement(this,i))
  615.                 mark(tmp);
  616.             break;
  617.         }
  618.         break;
  619.         }
  620.  
  621.     /* backup to a point where we can continue descending */
  622.     for (;;)
  623.  
  624.         /* make sure there is a previous node */
  625.         if (prev) {
  626.         if (prev->n_flags & LEFT) {    /* came from left side */
  627.             prev->n_flags &= ~LEFT;
  628.             tmp = car(prev);
  629.             rplaca(prev,this);
  630.             if (this = cdr(prev)) {
  631.             rplacd(prev,tmp);            
  632.             break;
  633.             }
  634.         }
  635.         else {                /* came from right side */
  636.             tmp = cdr(prev);
  637.             rplacd(prev,this);
  638.         }
  639.         this = prev;            /* step back up the branch */
  640.         prev = tmp;
  641.         }
  642.  
  643.         /* no previous node, must be done */
  644.         else
  645.         return;
  646.     }
  647. }
  648.  
  649. /* sweep - sweep all unmarked nodes and add them to the free list */
  650. LOCAL sweep()
  651. {
  652.     SEGMENT *seg;
  653.     LVAL p;
  654.     int n;
  655.  
  656.     /* empty the free list */
  657.     fnodes = NIL;
  658.     nfree = 0L;
  659.  
  660.     /* add all unmarked nodes */
  661.     for (seg = segs; seg; seg = seg->sg_next) {
  662.     if (seg == fixseg)     /* don't sweep the fixnum segment */
  663.         continue;
  664.     else if (seg == charseg) /* don't sweep the character segment */
  665.         continue;
  666.     p = &seg->sg_nodes[0];
  667.     for (n = seg->sg_size; --n >= 0; ++p)
  668.         if (!(p->n_flags & MARK)) {
  669.         switch (ntype(p)) {
  670.         case STRING:
  671.             if (getstring(p) != NULL) {
  672.                 total -= (long)getslength(p);
  673.                 free(getstring(p));
  674.             }
  675.             break;
  676.         case STREAM:
  677.             if (getfile(p))
  678.                 osclose(getfile(p));
  679.             break;
  680. #if (defined(UNIX) || defined(WINTERP))
  681.         case XLTYPE_PIPE: /* same as STREAM, except that pipes must be closed w/ pclose() */
  682.             if (getfile(p))
  683.                 pclose(getfile(p));    
  684.             break;
  685. #endif /* (defined(UNIX) || defined(WINTERP)) */
  686. #ifdef WINTERP
  687.         case XLTYPE_XmString:
  688.             Wxms_Garbage_Collect_XmString(p);
  689.             break;
  690.         case XLTYPE_Pixmap:
  691.             Wpm_Decr_Refcount_Or_Free_Pixmap(p); /* Tell Motif that the X11 Pixmap is no longer ref'd */
  692.             break;
  693.                 case XLTYPE_WIDGETOBJ:
  694.             /* During initialization (:isnew method), we stored
  695.                a pointer to WIDGETOBJ in the XmNuserData
  696.                resource. We must clear this since it will be
  697.                invalid after the WIDGETOBJ is garbage colected */
  698.             Wcls_Garbage_Collect_WIDGETOBJ(p);
  699.                 /* fall through to "VECTOR" case */
  700.             case XLTYPE_TIMEOUTOBJ:
  701.         case XLTYPE_CALLBACKOBJ:
  702.         case XLTYPE_PIXMAP_REFOBJ:
  703.                 case XLTYPE_EVHANDLEROBJ:
  704. #endif
  705.         case SYMBOL:
  706.         case OBJECT:
  707.         case VECTOR:
  708.         case CLOSURE:
  709.         case STRUCT:
  710.             if (p->n_vsize) {
  711.                 total -= (long) (p->n_vsize * sizeof(LVAL));
  712.                 free(p->n_vdata);
  713.             }
  714.             break;
  715.         }
  716.         p->n_type = FREE;
  717.         rplaca(p,NIL);
  718.         rplacd(p,fnodes);
  719.         fnodes = p;
  720.         nfree += 1L;
  721.         }
  722.         else
  723.         p->n_flags &= ~MARK;
  724.     }
  725. }
  726.  
  727. /* addseg - add a segment to the available memory */
  728. LOCAL int addseg()
  729. {
  730.     SEGMENT *newseg;
  731.     LVAL p;
  732.     int n;
  733.  
  734.     /* allocate the new segment */
  735.     if (anodes == 0 || (newseg = newsegment(anodes)) == NULL)
  736.     return (FALSE);
  737.  
  738.     /* add each new node to the free list */
  739.     p = &newseg->sg_nodes[0];
  740.     for (n = anodes; --n >= 0; ++p) {
  741.     rplacd(p,fnodes);
  742.     fnodes = p;
  743.     }
  744.  
  745.     /* return successfully */
  746.     return (TRUE);
  747. }
  748.  
  749. /* newsegment - create a new segment (only called here and in xlimage.c) */
  750. SEGMENT *newsegment(n)
  751.   int n;
  752. {
  753.     SEGMENT *newseg;
  754.  
  755.     /* allocate the new segment */
  756.     if ((newseg = (SEGMENT *)calloc(1,segsize(n))) == NULL)
  757.     return (NULL);
  758.  
  759.     /* initialize the new segment */
  760.     newseg->sg_size = n;
  761.     newseg->sg_next = NULL;
  762.     if (segs)
  763.     lastseg->sg_next = newseg;
  764.     else
  765.     segs = newseg;
  766.     lastseg = newseg;
  767.  
  768.     /* update the statistics */
  769.     total += (long)segsize(n);
  770.     nnodes += (long)n;
  771.     nfree += (long)n;
  772.     ++nsegs;
  773.  
  774.     /* return the new segment */
  775.     return (newseg);
  776. }
  777.  
  778. /* stats - print memory statistics */
  779. LOCAL stats()
  780. {
  781.     sprintf(buf,"Nodes:       %ld\n",nnodes); stdputstr(buf);
  782.     sprintf(buf,"Free nodes:  %ld\n",nfree);  stdputstr(buf);
  783.     sprintf(buf,"Segments:    %d\n",nsegs);   stdputstr(buf);
  784.     sprintf(buf,"Allocate:    %d\n",anodes);  stdputstr(buf);
  785.     sprintf(buf,"Total:       %ld\n",total);  stdputstr(buf);
  786.     sprintf(buf,"Collections: %d\n",gccalls); stdputstr(buf);
  787. }
  788.  
  789. /* xgc - xlisp function to force garbage collection */
  790. LVAL xgc()
  791. {
  792.     /* make sure there aren't any arguments */
  793.     xllastarg();
  794.  
  795.     /* garbage collect */
  796.     gc();
  797.  
  798.     /* return nil */
  799.     return (NIL);
  800. }
  801.  
  802. /* xexpand - xlisp function to force memory expansion */
  803. LVAL xexpand()
  804. {
  805.     LVAL num;
  806.     int n,i;
  807.  
  808.     /* get the new number to allocate */
  809.     if (moreargs()) {
  810.     num = xlgafixnum();
  811.     n = getfixnum(num);
  812.     }
  813.     else
  814.     n = 1;
  815.     xllastarg();
  816.  
  817.     /* allocate more segments */
  818.     for (i = 0; i < n; i++)
  819.     if (!addseg())
  820.         break;
  821.  
  822.     /* return the number of segments added */
  823.     return (cvfixnum((FIXTYPE)i));
  824. }
  825.  
  826. /* xalloc - xlisp function to set the number of nodes to allocate */
  827. LVAL xalloc()
  828. {
  829.     int n,oldn;
  830.     LVAL num;
  831.  
  832.     /* get the new number to allocate */
  833.     num = xlgafixnum();
  834.     n = getfixnum(num);
  835.  
  836.     /* make sure there aren't any more arguments */
  837.     xllastarg();
  838.  
  839.     /* set the new number of nodes to allocate */
  840.     oldn = anodes;
  841.     anodes = n;
  842.  
  843.     /* return the old number */
  844.     return (cvfixnum((FIXTYPE)oldn));
  845. }
  846.  
  847. /* xmem - xlisp function to print memory statistics */
  848. LVAL xmem()
  849. {
  850.     /* allow one argument for compatiblity with common lisp */
  851.     if (moreargs()) xlgetarg();
  852.     xllastarg();
  853.  
  854.     /* print the statistics */
  855.     stats();
  856.  
  857.     /* return nil */
  858.     return (NIL);
  859. }
  860.  
  861. #ifdef SAVERESTORE
  862. /* xsave - save the memory image */
  863. LVAL xsave()
  864. {
  865.     unsigned char *name;
  866.  
  867.     /* get the file name, verbose flag and print flag */
  868.     name = getstring(xlgetfname());
  869.     xllastarg();
  870.  
  871.     /* save the memory image */
  872.     return (xlisave(name) ? true : NIL);
  873. }
  874.  
  875. /* xrestore - restore a saved memory image */
  876. LVAL xrestore()
  877. {
  878.     extern jmp_buf top_level;
  879.     unsigned char *name;
  880.  
  881.     /* get the file name, verbose flag and print flag */
  882.     name = getstring(xlgetfname());
  883.     xllastarg();
  884.  
  885.     /* restore the saved memory image */
  886.     if (!xlirestore(name))
  887.     return (NIL);
  888.  
  889.     /* return directly to the top level */
  890.     stdputstr("[ returning to the top level ]\n");
  891.     longjmp(top_level,1);
  892. }
  893. #endif
  894.  
  895. /* xlminit - initialize the dynamic memory module */
  896. xlminit()
  897. {
  898.     LVAL p;
  899.     int i;
  900.  
  901.     /* initialize our internal variables */
  902.     segs = lastseg = NULL;
  903.     nnodes = nfree = total = 0L;
  904.     nsegs = gccalls = 0;
  905.     anodes = NNODES;
  906.     fnodes = NIL;
  907.  
  908.     /* allocate the fixnum segment */
  909.     if ((fixseg = newsegment(SFIXSIZE)) == NULL)
  910.     xlfatal("insufficient memory");
  911.  
  912.     /* initialize the fixnum segment */
  913.     p = &fixseg->sg_nodes[0];
  914.     for (i = SFIXMIN; i <= SFIXMAX; ++i) {
  915.     p->n_type = FIXNUM;
  916.     p->n_fixnum = i;
  917.     ++p;
  918.     }
  919.  
  920.     /* allocate the character segment */
  921.     if ((charseg = newsegment(CHARSIZE)) == NULL)
  922.     xlfatal("insufficient memory");
  923.  
  924.     /* initialize the character segment */
  925.     p = &charseg->sg_nodes[0];
  926.     for (i = CHARMIN; i <= CHARMAX; ++i) {
  927.     p->n_type = CHAR;
  928.     p->n_chcode = i;
  929.     ++p;
  930.     }
  931.  
  932.     /* initialize structures that are marked by the collector */
  933.     obarray = xlenv = xlfenv = xldenv = NIL;
  934.     s_gcflag = s_gchook = NIL;
  935. #ifdef WINTERP
  936.     v_savedobjs = NIL;
  937. #endif
  938.  
  939.     /* allocate the evaluation stack */
  940.     if ((xlstkbase = (LVAL **)malloc(EDEPTH * sizeof(LVAL *))) == NULL)
  941.     xlfatal("insufficient memory");
  942.     xlstack = xlstktop = xlstkbase + EDEPTH;
  943.  
  944.     /* allocate the argument stack */
  945.     if ((xlargstkbase = (LVAL *)malloc(ADEPTH * sizeof(LVAL))) == NULL)
  946.     xlfatal("insufficient memory");
  947.     xlargstktop = xlargstkbase + ADEPTH;
  948.     xlfp = xlsp = xlargstkbase;
  949.     *xlsp++ = NIL;
  950. }
  951.  
  952.